﻿#include "ssLeServer.h"
#include "net/ssNetBase.h"
#include "thread/ssThread.h"
#include "message/ssMsgIdDef.h"
#include "../ssServerErrorDefine.h"
#include "log/ssLogger.h"
#ifndef _WIN32
#include <arpa/inet.h>
#endif


namespace StarSeeker
{

ssLeServer::ssLeServer()
{
	m_base = 0;
	m_listener = 0;
	m_idAlloter.Init(1, 400000000);
	m_isClient = false;
	m_rwSize = 0;
	m_parsePackageMode = 0;
}

ssLeServer::~ssLeServer()
{
	StopServer();
}

void ssLeServer::StartDispatch()
{
	if (m_base)
	{
#ifdef _WIN32
		evthread_use_windows_threads();//win上设置
#else
		evthread_use_pthreads();    //unix上设置
#endif
		evthread_make_base_notifiable(m_base);

		event_base_dispatch(m_base);
	}
}

void ssLeServer::StopServer()
{
	if (m_listener)
	{
		evconnlistener_free(m_listener);
		m_listener = 0;
	}
	if (m_base)
	{
		event_base_loopbreak(m_base);
		event_base_free(m_base);
		m_base = 0;
	}
	//event_free(signal_event);
}

bool ssLeServer::CreateConnect(const char* ip, const u16 port)
{
	m_connectIP = ip;
	m_connectPort = port;
	m_isClient = true;

	m_base = event_base_new();
	if (!m_base)
	{
		SS_LOG->Print("Could not initialize libevent!");
		return false;
	}

	return Reconnect();
}

bool ssLeServer::Reconnect()
{
	if (m_isClient)
	{
		i32 err = 0;
		SOCKET s = INVALID_SOCKET;
		while (s == INVALID_SOCKET)
		{
			SS_LOG->PrintEx("connect to %s:%d", m_connectIP.c_str(), m_connectPort);
			err = ConnectToServer(m_connectIP.c_str(), m_connectPort, s);
			ssThreadBase::Sleep(5000);
		}
		Nonblock(s);
		//设置一下缓冲区的大小
		if (m_rwSize)
		{
			SetSendBuffer(s, m_rwSize);
			SetRecvBuffer(s, m_rwSize);
		}

		bufferevent* buff = 0;
		buff = bufferevent_socket_new(m_base, s, BEV_OPT_CLOSE_ON_FREE);// | BEV_OPT_THREADSAFE);
		if (buff == 0)
		{
			SS_LOG->Print("Could not create a bufferevent!");
			return false;
		}

		struct sockaddr_in server_addr;
		memset(&server_addr, 0, sizeof(server_addr));
		server_addr.sin_family = AF_INET;
		server_addr.sin_port = htons(m_connectPort);
		server_addr.sin_addr.s_addr = inet_addr(m_connectIP.c_str());

		//if (0 != bufferevent_socket_connect(buff, (struct sockaddr *)&server_addr, sizeof(server_addr)))
		//{
		//	return false;
		//}
		//SS_LOG->PrintEx("connect to %s:%d", m_connectIP.c_str(), m_connectPort);

		//分配一个连接对象
		//!!需要对象池
		ssLeSession* session = new ssLeSession();
		evutil_socket_t fd = bufferevent_getfd(buff);
		session->Init(this, 0, buff, fd, (sockaddr*)&server_addr);
		bufferevent_setcb(buff, conn_readcb, NULL, conn_errorcb, session);
		//bufferevent_enable(buff, EV_WRITE);
		bufferevent_enable(buff, EV_READ);// | EV_PERSIST);

		OnNewConnection(session);
		return true;
	}
	return false;
}

void ssLeServer::SetRWBufferSize(u32 len)
{
	if (len < 1024*1024*100)
	{
		m_rwSize = len;
	}
}

void ssLeServer::OnNewConnection(ssLeSession *session)
{
}

void ssLeServer::AfterSend(ssLeSession *session)
{
}

void ssLeServer::OnReceive(ssLeSession *session, char *data, u32 len)
{
	delete[] data;
}

void ssLeServer::OnError(ssLeSession *session, short error)
{
	delete session;
}

void ssLeServer::conn_writecb(bufferevent *bev, void *user_data)
{
	//struct evbuffer *output = bufferevent_get_input(bev);
	ssLeSession* s = (ssLeSession*)user_data;
	s->m_pServer->AfterSend(s);
}

void ssLeServer::conn_readcb(bufferevent *bev, void *user_data)
{
	struct evbuffer *input = bufferevent_get_input(bev);
	ssLeSession* s = (ssLeSession*)user_data;
	char* data = 0;
	//获取相关的完成数据
	bufferevent_disable(bev, EV_READ);
	u32 len = evbuffer_get_length(input);
	if (s && len > 0)
	{
		data = s->BevRead(input, len);
	}
	bufferevent_enable(bev, EV_READ);
	if (data)
	{
		s->m_pServer->OnReceive(s, data, len);
	}

    //char tmpbuff[10240];
    //u32 len = bufferevent_read(bev, tmpbuff, 10240);
    //bufferevent_write(bev, tmpbuff, len);
    //int a = *(int*)(tmpbuff+20);
    //printf("%d\n", a);
}

void ssLeServer::conn_errorcb(bufferevent *bev, short error, void *ctx)
{
	short err = 0;
	if (error & BEV_EVENT_EOF)
	{
		/* connection has been closed, do any clean up here */
		err = SS_DISCONNECT;
	}
	else if (error & BEV_EVENT_ERROR)
	{
		/* check errno to see what error occurred */
		err = SS_SOCKET_ERROR;
	}
	else if (error & BEV_EVENT_TIMEOUT)
	{
		/* must be a timeout event handle, handle it */
		err = SS_CONNECT_TIMEOUT;
	}
	else if (error & BEV_EVENT_CONNECTED)//连接服务器成功
	{
		return;
	}
	//这将自动close套接字和free读写缓冲区
	//bufferevent_free(bev);
	//通知上层
	ssLeSession* s = (ssLeSession*)ctx;
	if (s)
	{
		s->PostClose(err);
		s->m_pServer->OnError(s, err);
	}
}

void ssLeServer::conn_signalcb(evbuffer* bev, const evbuffer_cb_info* info, void* ctx)
{

}

void ssLeServer::accept_cb(evconnlistener *listener, evutil_socket_t fd, sockaddr *sa, int socklen, void *user_data)
{
	ssLeServer* pserver = (ssLeServer*)user_data;
	struct event_base *base = pserver->m_base;
	struct bufferevent *bev;

	//设置FD为非阻塞
	evutil_make_socket_nonblocking(fd);
	//设置一下缓冲区的大小
	if (pserver->m_rwSize)
	{
		SOCKET s = (SOCKET)fd;
		SetSendBuffer(s, pserver->m_rwSize);
		SetRecvBuffer(s, pserver->m_rwSize);
	}

	bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
	if (!bev)
	{
		SS_LOG->Print("ssLeServer::listener_cb bufferevent_socket_new error!");
		event_base_loopbreak(base);
		return;
	}
	//struct evbuffer *input = bufferevent_get_input(bev);
	//struct evbuffer *output = bufferevent_get_output(bev);
	//evbuffer_enable_locking(input, NULL);
	//evbuffer_enable_locking(output, NULL);

	//分配一个连接对象
	//!!需要对象池
	ssLeSession* session = new ssLeSession();
	session->Init(pserver, pserver->m_idAlloter.GetID(), bev, fd, sa);

	bufferevent_setcb(bev, conn_readcb, 0, conn_errorcb, session);
	//bufferevent_enable(bev, EV_WRITE);
	bufferevent_enable(bev, EV_READ);

	pserver->OnNewConnection(session);
}

bool ssLeServer::CreateListen(const char* ip, const u16 port)
{
	m_connectIP = ip;
	m_connectPort = port;

	m_base = event_base_new();
	if (!m_base)
	{
		SS_LOG->Print("Could not create a bufferevent!");
		return false;
	}

	struct sockaddr_in sin;
	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = inet_addr(ip);

	m_listener = evconnlistener_new_bind(m_base, accept_cb, (void *)this,
		LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&sin, sizeof(sin));
	if (!m_listener)
	{
		SS_LOG->Print("Could not create a listener!");
		return false;
	}

	//signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
	//if (!signal_event || event_add(signal_event, NULL) < 0) {
	//	fprintf(stderr, "Could not create/add a signal event!\n");
	//	return 1;
	//}

	SS_LOG->PrintEx("start listen %s:%d", ip, port);

	return true;
}

}
